package com.totoro.algorithm;

import com.sun.imageio.plugins.common.ImageUtil;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

/**
 * 差异哈希算法/Difference hash algorithm/HA
 * <p>
 * 最适用于缩略图，放大图搜索
 * <p>
 * 相比pHash，dHash的速度要快的多<br>
 * 相比aHash，dHash在效率几乎相同的情况下的效果要更好，它是<b>基于渐变</b>实现的。
 * <p>
 */
public class DifferenceHashAlgorithm {

    private static ColorConvertOp colorConvert = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);

    private static BufferedImage grayscale(BufferedImage img) {
        colorConvert.filter(img, img);
        return img;
    }

    private static int getBlue(BufferedImage img, int x, int y) {
        return (img.getRGB(x, y)) & 0xff;
    }

    /**
     * 图片指纹
     *
     * @param imagePath
     * @return
     * @throws IOException
     */
    public static String fingerprint(String imagePath) throws IOException {
        File file = new File(imagePath);
        BufferedImage srcImage = ImageIO.read(file);
        /*
         * 1.缩小尺寸. 收缩到9*8的大小，一遍它有72的像素点
         */
        BufferedImage image9x8 = resize(srcImage, 9, 8);
        /*
         * 2.简化色彩,转化为灰度图. 把缩放后的图片转化为256阶的灰度图
         */
        image9x8 = grayscale(image9x8);

        int[][] grayPix = new int[8][9];

        for (int x = 0; x < image9x8.getHeight(); x++) {
            for (int y = 0; y < image9x8.getWidth(); y++) {
                grayPix[x][y] = getBlue(image9x8, y, x);
            }
        }
        /*int width = image9x8.getWidth();
        int height = image9x8.getHeight();
        int[] grayPix = new int[width * height];
        int i = 0;
        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                int rgb = image9x8.getRGB(x, y);
                int r = rgb >> 16 & 0xff;
                int g = rgb >> 8 & 0xff;
                int b = rgb >> 0 & 0xff;
                int gray = (r * 30 + g * 59 + b * 11) / 100;
                grayPix[i++] = gray;
            }
        }*/
        /*
         * 4.计算差异值：dHash算法工作在相邻像素之间，这样每行9个像素之间产生了8个不同的差异，一共8行，则产生了64个差异值.
         * 5.获取指纹.如果左边的像素比右边的更亮，则记录为1，否则为0.
         */
        StringBuffer figure = new StringBuffer();
        for (int k = 0; k < grayPix.length; k++) {
            for (int j = 0; j < grayPix[k].length - 1; j++) {
                long b = grayPix[k][j] > grayPix[k][j + 1] ? 1 : 0;
                //figure |= b << i;
                figure.append(b);
            }
        }

        return figure.toString();
    }

    /**
     * 图片尺寸等比缩小
     *
     * @param image
     * @param width
     * @param height
     * @return
     */
    private static BufferedImage resize(BufferedImage image, int width, int height) {
        BufferedImage resizedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = resizedImage.createGraphics();
        g.drawImage(image, 0, 0, width, height, null);
        g.dispose();
        return resizedImage;
    }

    public static int distance(String s1, String s2) {
        int counter = 0;
        for (int k = 0; k < s1.length(); k++) {
            if (s1.charAt(k) != s2.charAt(k)) {
                counter++;
            }
        }
        return counter;
    }

    public static boolean imgChk(String img1, String img2, int tv) {
        String image1;
        String image2;

        try {
            Long start = System.currentTimeMillis();
            image1 = fingerprint(img1) + "";
            System.out.println("耗时1：" + (System.currentTimeMillis() - start) + "ms");
            System.out.println("哈希值1：" + image1);
            start = System.currentTimeMillis();
            image2 = fingerprint(img2) + "";
            System.out.println("耗时2：" + (System.currentTimeMillis() - start) + "ms");
            System.out.println("哈希值2：" + image2);

            int dt = distance(image1, image2);
            System.out.println("[" + img1 + "] : [" + img2 + "] Score is " + dt);
            if (dt <= tv)
                return true;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }
}
